#include "string_util/string_util.h"
#include "stun_protocol/stun_protocol_parser.h"

#include <arpa/inet.h>
#include <cstdint>
#include <cstdio>
#include <gtest/gtest.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <vector>

TEST(StunRequest, Test)
{
    std::string          message = "000100002112a442cda344c6ffa066d311b63dac";
    std::vector<uint8_t> content;
    StringUtil::HexStrToCharactor(message, content);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(content.data(), content.size(), length);
    EXPECT_EQ(result, StunProtocolParser::FINISH);
    EXPECT_EQ(content.size(), length);
    printf("content size : %ld and length : %d.\n", content.size(), length);
}

TEST(StunResponse, Test)
{
    std::string          message = "0101000c2112a442cda344c6ffa066d311b63dac0020000800014cd45d5dc763";
    std::vector<uint8_t> content;
    StringUtil::HexStrToCharactor(message, content);
    StunProtocolParser paser;
    int                length = 0;
    paser.ParserStunMsg(content.data(), content.size(), length);
}

TEST(StunResponse, TestV6)
{
    std::string message = "010100182112a442124add96ab65282faf39b2b9002000140002925d051cafcd8319d29602864a98a4f85530";
    std::vector<uint8_t> content;
    StringUtil::HexStrToCharactor(message, content);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(content.data(), content.size(), length);
}

TEST(StunRequest, AllocateUDP)
{
    std::string          message = "000300082112a442596a6569435631636e64634b0019000411000000";
    std::vector<uint8_t> content;
    StringUtil::HexStrToCharactor(message, content);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(content.data(), content.size(), length);
}

TEST(StunResponse, MappedAddress)
{
    std::string message = "010100182112a442626e6369634b37574b62356b0001000800011f9c7c4f3f840020000800013e8e5d5d9bc6";
    std::vector<uint8_t> content;
    StringUtil::HexStrToCharactor(message, content);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(content.data(), content.size(), length);
}

TEST(StunRequest, BindRequest)
{
    std::string          message = "010100142112a44271554765446d69736272676e0020000800013e755d5d9bc680280004df88ef86";
    //        "0001004c2112a4423033444b47332b556971545900060009753356673a65397433000000c0570004000003e78029000895040b90e007c71d002400046e001eff000800143823cb00648b95ba2cfc167d25c4f1ead02a600b8028000454ef79ac";
    std::vector<uint8_t> content;
    StringUtil::HexStrToCharactor(message, content);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(content.data(), content.size(), length);
}

TEST(XORMapp, Test)
{
    char                ip[129] = {};
    std::string         addr    = "240e:b8f:9153:f00:a9e3:62b7:bc1:e789";
    struct sockaddr_in6 dst     = {};
    inet_pton(AF_INET6, addr.c_str(), &dst.sin6_addr);
    std::string c;
    StringUtil::DataToHexStr(&dst.sin6_addr, sizeof(dst.sin6_addr), c);
    printf("%s.\n", c.c_str());
    uint8_t * ptr = (uint8_t *)&dst.sin6_addr;
    printf("0x%02x--0x%02x.\n", *(ptr), *(ptr) ^ 0x21);
    printf("0x%02x.\n", *(ptr + 1) ^ 0x12);
    printf("0x%02x.\n", *(ptr + 2) ^ 0xa4);
    printf("0x%02x.\n", *(ptr + 3) ^ 0x42);
    printf("0x%02x.\n", *(ptr + 4) ^ 0x12);
    printf("0x%02x.\n", *(ptr + 5) ^ 0x4a);
    printf("0x%02x.\n", *(ptr + 6) ^ 0xdd);
    printf("0x%02x.\n", *(ptr + 7) ^ 0x96);
    printf("0x%02x.\n", *(ptr + 8) ^ 0xab);
    inet_ntop(AF_INET6, &dst.sin6_addr, ip, 129);
    printf("result : %s.\n", ip);
}

TEST(RequestMessage, BindRequest)
{
    //                              000100002112a442cda344c6ffa066d311b63dac.
    std::string          content = "000100002112a442cda344c6ffa066d311b63dac";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharactor(content, data);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(data.data(), data.size(), length);
    EXPECT_EQ(result, StunProtocolParser::FINISH);

    std::vector<uint8_t> compose_data(100);
    length = parser.ComposeStunMsg(compose_data.data(), 100);
    std::string hex_result;
    StringUtil::DataToHexStr(compose_data.data(), length, hex_result);
    printf("compose stun msg:%s.\n", hex_result.c_str());
    EXPECT_EQ(content, hex_result);
    printf("hex result length:%lu and result length : %d.\n", hex_result.size(), length);
}

TEST(ResponseType, BindSuccessResponse)
{
    //                     0101000c2112a442cda344c6ffa066d311b63dac0020000800014cd45d5dc763
    std::string          content = "0101000c2112a442cda344c6ffa066d311b63dac0020000800014cd45d5dc763";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharactor(content, data);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(data.data(), data.size(), length);
    EXPECT_EQ(result, StunProtocolParser::FINISH);

    std::vector<uint8_t> compose_data(200);
    length = parser.ComposeStunMsg(compose_data.data(), 100);
    std::string hex_result;
    StringUtil::DataToHexStr(compose_data.data(), length, hex_result);
    printf("raw     stun msg:%s.\n", content.c_str());
    printf("compose stun msg:%s.\n", hex_result.c_str());
    EXPECT_EQ(content, hex_result);
    printf("hex result length:%lu and result length : %d.\n", hex_result.size(), length);
}

TEST(ResponseType, BindSuccessResponseV6)
{
    //                     010100182112a442124add96ab65282faf39b2b9002000140002925d051cafcd8319d29602864a98a4f85530
    std::string content = "010100182112a442124add96ab65282faf39b2b9002000140002925d051cafcd8319d29602864a98a4f85530";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharactor(content, data);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(data.data(), data.size(), length);
    EXPECT_EQ(result, StunProtocolParser::FINISH);

    std::vector<uint8_t> compose_data(200);
    length = parser.ComposeStunMsg(compose_data.data(), 100);
    std::string hex_result;
    StringUtil::DataToHexStr(compose_data.data(), length, hex_result);
    printf("raw     stun msg:%s.\n", content.c_str());
    printf("compose stun msg:%s.\n", hex_result.c_str());
    EXPECT_EQ(content, hex_result);
    printf("hex result length:%lu and result length : %d.\n", hex_result.size(), length);
}

TEST(ResponseType, AddrMapped)
{
    //                     010100182112a44241694c6c58513074464c2b610001000800011f607c4f3f840020000800013e725d5d9bc6
    std::string content = "010100182112a44241694c6c58513074464c2b610001000800011f607c4f3f840020000800013e725d5d9bc6";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharactor(content, data);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(data.data(), data.size(), length);
    EXPECT_EQ(result, StunProtocolParser::FINISH);

    std::vector<uint8_t> compose_data(200);
    length = parser.ComposeStunMsg(compose_data.data(), 100);
    std::string hex_result;
    StringUtil::DataToHexStr(compose_data.data(), length, hex_result);
    printf("raw     stun msg:%s.\n", content.c_str());
    printf("compose stun msg:%s.\n", hex_result.c_str());
    EXPECT_EQ(content, hex_result);
    printf("hex result length:%lu and result length : %d.\n", hex_result.size(), length);
}

TEST(RequestType, Allocator)
{
    //                     000300082112a442436f346e502b3069726361490019000411000000
    std::string          content = "000300082112a442436f346e502b3069726361490019000411000000";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharactor(content, data);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(data.data(), data.size(), length);
    EXPECT_EQ(result, StunProtocolParser::FINISH);

    std::vector<uint8_t> compose_data(200);
    length = parser.ComposeStunMsg(compose_data.data(), 100);
    std::string hex_result;
    StringUtil::DataToHexStr(compose_data.data(), length, hex_result);
    printf("raw     stun msg:%s.\n", content.c_str());
    printf("compose stun msg:%s.\n", hex_result.c_str());
    EXPECT_EQ(content, hex_result);
    printf("hex result length:%lu and result length : %d.\n", hex_result.size(), length);
}

TEST(ResponseType, FingerPrint)
{
    //                              010100142112a44271554765446d69736272676e0020000800013e755d5d9bc680280004df88ef86
    std::string          content = "010100142112a44271554765446d69736272676e0020000800013e755d5d9bc680280004df88ef86";
    std::vector<uint8_t> data;
    StringUtil::HexStrToCharactor(content, data);
    StunProtocolParser parser;
    int                length = 0;
    int                result = parser.ParserStunMsg(data.data(), data.size(), length);
    EXPECT_EQ(result, StunProtocolParser::FINISH);

    std::vector<uint8_t> compose_data(200);
    length = parser.ComposeStunMsg(compose_data.data(), 100);
    std::string hex_result;
    StringUtil::DataToHexStr(compose_data.data(), length, hex_result);
    printf("raw     stun msg:%s.\n", content.c_str());
    printf("compose stun msg:%s.\n", hex_result.c_str());
    EXPECT_EQ(content, hex_result);
    printf("hex result length:%lu and result length : %d.\n", hex_result.size(), length);
}
